Angular6で”global is not defined”が出た時の回避策
概要
どうも!クラスメソッドの岡です。
Angular6とAmplifyのcognitoパッケージでログイン画面を作成しようとしたら以下のエラーが発生して、原因が分からずかなり時間を消費しました。
Uncaught ReferenceError: global is not defined
調べて見ると、Amplifyに限らずAngular6とglobalオブジェクトを参照する外部ライブラリを利用している環境で発生してるようです。 Angular6のアップデートでNode.jsと外部ライブラリ間のshimを削除したのが原因のようです。 Angularのエラーではないので、Amplifyのアップデートまでの回避策として以下を実行しました。
詳細
環境
Angular
$ ng -v Angular CLI: 6.0.0 Node: 10.0.0 OS: darwin x64 Angular: 6.0.2 ... animations, cdk, common, compiler, compiler-cli, core, forms ... http, language-service, material, platform-browser ... platform-browser-dynamic, router Package Version ----------------------------------------------------------- @angular-devkit/architect 0.6.3 @angular-devkit/build-angular 0.6.3 @angular-devkit/build-optimizer 0.6.3 @angular-devkit/core 0.6.3 @angular-devkit/schematics 0.6.3 @angular/cli 6.0.0 @ngtools/webpack 6.0.3 @schematics/angular 0.6.3 @schematics/update 0.6.3 rxjs 6.1.0 typescript 2.7.2 webpack 4.8.3
Amplify
$ npm outdated aws-amplify Package Current Wanted Latest Location aws-amplify 0.4.0 0.4.1 0.4.1 management-console-test
期待する動作
実装した画面はこんな感じです。
実装コード(抜粋)
export const environment = { production: false, amplify: { Auth: { region: 'ap-northeast-1', userPoolId: 'ap-northeast-xxxxxxx' // ユーザープールのIDを入力, userPoolWebClientId: 'xxxxxxxxxxxxxx' // 追加したアプリクライアントのIDを入力} } };
import { Injectable } from '@angular/core'; import { Router } from '@angular/router'; import { Observable, of, BehaviorSubject, from } from 'rxjs'; import { map, tap, catchError } from 'rxjs/operators'; import Amplify, { Auth } from 'aws-amplify'; import { environment } from './../../environments/environment'; @Injectable() export class AuthService { public loggedIn: BehaviorSubject<boolean>; constructor( private router: Router ) { Amplify.configure(environment.amplify); this.loggedIn = new BehaviorSubject<boolean>(false); } // サインアップ public signUp(userid, password): Observable<any> { return from(Auth.signUp(userid, password)); } // サインアップの検証 public confirmSignUp(userid, code): Observable<any> { return from(Auth.confirmSignUp(userid, code)); } // ログイン public signIn(userid, password): Observable<any> { return from(Auth.signIn(userid, password)) .pipe( tap(() => this.loggedIn.next(true)) ); } // ログイン状態の取得 public isAuthenticated(): Observable<boolean> { return from(Auth.currentAuthenticatedUser()) .pipe( map(result => { this.loggedIn.next(true); return true; }), catchError(error => { this.loggedIn.next(false); return of(false); }) ); } // ログアウト public signOut() { from(Auth.signOut()) .subscribe( result => { this.loggedIn.next(false); this.router.navigate(['/login']); }, error => console.log(error) ); } }
import { Component, OnInit } from '@angular/core'; import { AuthService } from './../services/auth.service'; import { Router } from '@angular/router'; import { FormControl, FormGroup, Validators, FormBuilder } from '@angular/forms'; @Component({ selector: 'app-login', templateUrl: './login.component.html', styleUrls: ['./login.component.css'] }) export class LoginComponent implements OnInit { title = '管理コンソール ログインページ'; public loginForm: FormGroup; constructor( private formbuilder: FormBuilder, private auth: AuthService, private router: Router ) { } ngOnInit() { this.initForm(); } initForm() { this.loginForm = this.formbuilder.group({ 'userid': ['', Validators.required], 'password': ['', Validators.required] }); } onSubmitLogin(value: any) { const userid = value.userid, password = value.password; this.auth.signIn(userid, password) .subscribe( result => { this.router.navigate(['/dashboard']); }, error => { console.log(error); alert('ログインに失敗しました。'); }); } }
エラー内容
上記の実装でコンパイルは成功しますが画面が表示されません。(!)
chromeの検証ページからコンソールを開くと以下のエラーが表示されていました。
Uncaught ReferenceError: global is not defined
回避策
polyfills.tsの末尾に以下を追記します。
// "global is not defined"の対応 (window as any).global = window;
もう一度ng serveで開いてみます。
またエラーが出ました。
Uncaught ReferenceError: Buffer is not defined
今度はBufferが見つからないようです。
再度、polyfills.tsの末尾に以下を追記します。
// "Buffer is not defined"の対応 global.Buffer = global.Buffer || require('buffer').Buffer;
すると、無事開けるようになりました。
まとめ
Angular6へのアップデートでNode.jsと外部ライブラリ間のshimを削除したと書かれています。
Node.jsのドキュメントを見るとBufferも削除されていました。→Node.js8
Angularのコンパイル環境がNode.jsに適応した形なので、外部ライブラリが適応するまでは上記のように手動でシミングしましょう。
2018/06/06追記
Amplifyの公式ドキュメントにも追記されていました。
↓↓↓